﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using CommandSystem;
using CustomCharacter;
using CustomCharacter.Ability;
using CustomCharacter.Interfaces;
using CustomCharacter.VoiceChat;
using Exiled.API.Enums;
using Exiled.API.Extensions;
using Exiled.API.Features;
using Exiled.API.Features.Pools;
using Exiled.Events.EventArgs.Interfaces;
using Exiled.Events.EventArgs.Player;
using Exiled.Events.EventArgs.Scp914;
using InventorySystem.Items.MicroHID;
using MEC;
using PlayerRoles;
using PlayerStatsSystem;
using RemoteAdmin;
using RgCore.CustomSide;
using RgCore.Events;
using RgCore.Misc;
using RgCore.PlayerHud;
using UnityEngine;

namespace Scp2686
{
    [RoleInfo("SCP-2686", "Scp2686", RoleTypeId.ClassD, RoleTypeId.Tutorial, MaxHealth = 300)]
    public sealed class Scp2686(int id) : CustomCharacter.CustomCharacter(id), IScpNumber, IRoundStartSpawn,
        ITrialCard, ICustomSpawnpoint, ICustomRotation
    {
        public override Color32 RoleColor { get; } =
            new Color32(196, 76, 29, 255);


        public string ScpNumber => "2686";

        public byte MinPlayers => 30;

        public int Cost => 450;

        public Vector3 SpawnPosition { get; } = new(136.5f, 995.5f, -22.5f);

        public Quaternion DefaultRotation { get; } = new(0, 1, 0, 0);

        private const int BOOST_ENERGY_COUNT = 10;
        private const int BOOST_HEALTH_COUNT = 25;
        private const int MIN_RECOVER_ENERGY = 20;

        [Description("能量")]
        public string EnergyStr
        {
            get
            {
                AbilityInfo ab = Player.GetAbility("Scp2686_Attribute_1");
                return ab.Ability == null ? "null" : $"{ab.Datas["energy"]}/{ab.Datas["MAX_ENERGY"]}";
            }
        }

        [Description("团队人数")] public int TeamSize => SCP2686Team.Count();

        public static IEnumerable<Player> SCP2686Team =>
            AllCharacters.Where(player => player is Scp26862).Select(player => player.Player);

        public override IEnumerable<Ability> AbilityRegister()
        {
            CustomSide.TryCreate("Scp2686", "SCP-2686", Misc.AllowedColors[Misc.PlayerInfoColorTypes.Orange], false, (info) =>
            {
                return info.SideAlives["Scp2686"] == info.AlivesWithoutNeutral ? true : null;
            });
            return
            [
                new Ability("Scp2686_Offensive_1",
                    $"消耗自身一半的能量值，并将其平均分给(最低每人会分配到{MIN_RECOVER_ENERGY}能量)周围30M内的SCP2686-2.", AbilityType.Offensive, 30u,
                    Scp2686_Offensive_1_Function,
                    Scp2686_Offensive_1_Checker, null, null, GetType()),
                new Ability("Scp2686_Offensive_2", "消耗100能量值，将正在持有的小型电磁炮重新充能", AbilityType.Offensive, 60u,
                    Scp2686Team_Offensive_2_Function,
                    Scp2686Team_Offensive_2_Checker, null, null, GetType()),
                new Ability("Scp2686Team_Offensive_3", "消耗200能量值，立刻回满自己的生命值，并持续2秒无敌", AbilityType.Offensive, 150u,
                    Scp2686Team_Offensive_3_Function, Scp2686Team_Offensive_3_Checker, null, null, GetType(),
                    typeof(Scp26862)),
                new Ability("Scp2686_Passive_1", "击杀或捆绑敌人来同化对方.", AbilityType.Passive, 10u,
                    Scp2686_Passive_1_Function,
                    Scp2686_Passive_1_Checker,
                    [
                        Exiled.Events.Handlers.Player.Handcuffing,
                        EventProcessor.OnDying
                    ], null, GetType()),
                new AttributeAbility("Scp2686_Attribute_1", "SCP-2686特性", Scp2686_Attribute_1, true,
                [
                    Exiled.Events.Handlers.Player.DroppingItem,
                    Exiled.Events.Handlers.Player.DroppingAmmo,
                    Exiled.Events.Handlers.Player.SearchingPickup,
                    Exiled.Events.Handlers.Player.Handcuffing,
                    EventProcessor.OnHurting,
                    Exiled.Events.Handlers.Player.Died,
                    Exiled.Events.Handlers.Player.ItemRemoved,
                    Exiled.Events.Handlers.Player.ReloadingWeapon,
                    Exiled.Events.Handlers.Player.UnloadingWeapon,
                    Exiled.Events.Handlers.Scp914.UpgradingInventoryItem,
                ], [
                    new KeyValuePair<string, object>("gun_serial", null),
                    new KeyValuePair<string, object>("energy", 0),
                    new KeyValuePair<string, object>("MAX_ENERGY", 200)
                ], GetType())
            ];
        }
        private AbilityOutput Scp2686Team_Offensive_2_Function(Player player, ref AbilityInfo info,
            IExiledEvent exiledEvent,
            AbilityTrigger trigger)
        {
            AbilityInfo ab = GetScp2686Attribute(player);
            if (ab.Ability == null)
            {
                return new AbilityOutput(false, "此技能需要SCP2686的特性技能才可以使用");
            }

            if (CustomItem.CustomItem.GetItem(player.CurrentItem.Serial) is not MiniMicroHID.MiniMicroHID
                {
                    Base: MicroHIDItem microHIDItem
                })
            {
                return new AbilityOutput(false);
            }

            microHIDItem.Recharge();
            ab.Datas["energy"] = (int)ab.Datas["energy"] - 100;
            return new AbilityOutput(true, "成功充电!");
        }

        private static bool Scp2686Team_Offensive_2_Checker(Player instance, out string response)
        {
            AbilityInfo ab = GetScp2686Attribute(instance);
            if (ab.Ability is null)
            {
                ab = instance.GetAbility("Scp26862_Attribute_1");
            }

            if (ab.Ability == null)
            {
                response = "此技能需要SCP-2686的特性技能才可以使用";
                return false;
            }

            if ((int)ab.Datas["energy"] < 100)
            {
                response = "此技能释放需要100能量";
                return false;
            }

            if (instance.CurrentItem is null ||
                CustomItem.CustomItem.GetItem(instance.CurrentItem.Serial) is not MiniMicroHID.MiniMicroHID
                {
                    Base: MicroHIDItem microHIDItem
                })
            {
                response = "你并没有拿着微型电磁炮";
                return false;
            }

            if (microHIDItem.RemainingEnergy >= 1)
            {
                response = "现在电磁炮是满电哦";
                return false;
            }

            response = "";
            return true;
        }

        private static AbilityOutput Scp2686_Passive_1_Function(Player player, ref AbilityInfo info, IExiledEvent e,
            AbilityTrigger trigger)
        {
            AbilityInfo ab = player.GetAbility("Scp2686_Attribute_1");
            if (ab.Ability == null)
            {
                return new AbilityOutput(false, "此技能需要SCP-2686的特性技能才可以使用");
            }

            Player target = null;
            if (e is HandcuffingEventArgs handcuffingEventArgs && handcuffingEventArgs.Player == player)
            {
                if (handcuffingEventArgs.Target.GetCharacterInstance() != null)
                    return new AbilityOutput(false, "不可以选择特殊角色,所以没有打上标记哦!");
                handcuffingEventArgs.IsAllowed = false;
                target = handcuffingEventArgs.Target;
            }

            bool consume = false;
            if (e is DyingEventArgs dying && dying.Attacker == player)
            {
                if (dying.Player.GetCharacterInstance() != null || dying.Player.IsScp)
                    return new AbilityOutput(false, "不可以选择特殊角色,所以没有打上标记哦!");
                dying.IsAllowed = false;
                target = dying.Player;
                target.Health = target.MaxHealth;
                consume = true;
            }

            if (target == null)
                return false;
            if (consume)
            {
                ab.Datas["energy"] = (int)ab.Datas["energy"] - 50;
            }

            ab.Datas["MAX_ENERGY"] = (int)ab.Datas["MAX_ENERGY"] + BOOST_ENERGY_COUNT;
            player.MaxHealth += BOOST_HEALTH_COUNT;
            player.Health += BOOST_HEALTH_COUNT;
            target.DropItems();
            SpawnPlayer(target, typeof(Scp26862), RoleSpawnFlags.None);
            player.AddScore(50, "同化SCP-2686-2");
            return new AbilityOutput(consume);
        }

        private static bool Scp2686_Passive_1_Checker(Player instance, out string response)
        {
            AbilityInfo ab = instance.GetAbility("Scp2686_Attribute_1");
            if (ab.Ability == null)
            {
                response = "此技能需要SCP-2686的特性技能才能正常使用";
                return false;
            }

            int energy = (int)ab.Datas["energy"];

            if (energy < 50)
            {
                response = "当前能量不足以转化";
                return false;
            }

            response = "";
            return true;
        }

        private static bool Scp2686Team_Offensive_3_Checker(Player instance, out string response)
        {
            AbilityInfo ab = GetScp2686Attribute(instance);
            if (ab.Ability == null)
            {
                response = "此技能需要SCP-2686的特性技能才能正常使用";
                return false;
            }

            int energy = (int)ab.Datas["energy"];
            if (energy < 200)
            {
                response = "此技能至少需要200能量值才可以发动";
                return false;
            }

            if (instance.MaxHealth <= instance.Health)
            {
                response = "你现在就是最大血量哦";
                return false;
            }

            response = "";
            return true;
        }

        private static AbilityOutput Scp2686Team_Offensive_3_Function(Player player, ref AbilityInfo info,
            IExiledEvent exiledEvent, AbilityTrigger trigger)
        {
            if (trigger == AbilityTrigger.Active)
            {
                AbilityInfo ab = GetScp2686Attribute(player);
                if (ab.Ability == null)
                {
                    return new AbilityOutput(false, "此技能需要SCP-2686的特性技能才能正常使用");
                }

                ab.Datas["energy"] = ((int)ab.Datas["energy"]) - 200;
                player.Health = player.MaxHealth;
                player.IsGodModeEnabled = true;
                Timing.CallDelayed(2.0f, () => player.IsGodModeEnabled = false);
                return new AbilityOutput(true, "成功使用");
            }

            return new AbilityOutput(false);
        }

        private static AbilityOutput Scp2686_Offensive_1_Function(Player player, ref AbilityInfo info,
            IExiledEvent exiledEvent, AbilityTrigger trigger)
        {
            AbilityInfo ab = GetScp2686Attribute(player);
            if (ab.Ability is null)
            {
                return new AbilityOutput(false, "此技能需要SCP-2686的特性技能才能正常使用");
            }

            List<Player> allocationList =
                ListPool<Player>.Pool.Get(SCP2686Team.Where(p => Vector3.Distance(p.Position, player.Position) <= 30f));
            int energyAllocation = (int)Math.Ceiling((int)ab.Datas["energy"] / 2.0);
            int energyCount =
                (int)Math.Ceiling((double)Math.Max(MIN_RECOVER_ENERGY, energyAllocation / allocationList.Count));
            foreach (AbilityInfo ab2686 in allocationList.Select(GetScp2686Attribute)
                         .Where(ab2686 => ab2686.Ability is not null))
            {
                ab2686.Datas["energy"] = (int)ab2686.Datas["energy"] + energyCount;
            }

            ListPool<Player>.Pool.Return(allocationList);
            return new AbilityOutput(true, $"正在为队友恢复能量,每位SCP-2686-2预计恢复<color=yellow> {energyCount}</color> 点");
        }

        private static bool Scp2686_Offensive_1_Checker(Player instance, out string response)
        {
            AbilityInfo ab = instance.GetAbility("Scp2686_Attribute_1");
            if (ab.Ability == null)
            {
                response = "此技能需要SCP-2686的特性技能才能正常使用";
                return false;
            }

            if ((int)ab.Datas["energy"] < 80)
            {
                response = "此技能至少需要80能量值才可以发动";
                return false;
            }

            if (!SCP2686Team.Any())
            {
                response = "你没有招揽任何SCP-2686-2哦";
                return false;
            }

            if (!SCP2686Team.Any(p =>
                    Vector3.Distance(instance.Position, p.Position) <= 30f))
            {
                response = "没有任何SCP-2686-2在你的30m范围内";
                return false;
            }

            response = "";
            return true;
        }

        private static AbilityOutput Scp2686_Attribute_1(Player player, ref AbilityInfo info, IExiledEvent exiledEvent,
            AbilityTrigger trigger)
        {
            ushort serial = ((ushort?)info.Datas["gun_serial"]) ?? player.AddItem(FirearmType.Com18, null).Serial;
            if (info.Datas["gun_serial"] is null)
            {
                info.Datas["gun_serial"] = serial;
                player.Inventory.ServerSelectItem(serial);
            }

            int energy = (int)info.Datas["energy"];
            if (exiledEvent is null)
            {
                energy = Math.Min(energy + 3, (int)info.Datas["MAX_ENERGY"]);
            }

            if (exiledEvent is DroppingItemEventArgs { IsAllowed: true } droppingItemEventArgs &&
                droppingItemEventArgs.Player == player && droppingItemEventArgs.Item.Serial == serial)
            {
                droppingItemEventArgs.IsAllowed = false;
                player.DeleteMsg("scp2686_hint", update: false);
                droppingItemEventArgs.Player.SendRawMsg("scp2686_hint", "你没法丢掉这把神奇的COM-18!", 3u,
                    ScreenLocation.CenterTop, update: true);
            }

            if (exiledEvent is DroppingAmmoEventArgs { IsAllowed: true } droppingAmmoEventArgs &&
                droppingAmmoEventArgs.Player == player)
            {
                droppingAmmoEventArgs.IsAllowed = false;
                player.DeleteMsg("scp2686_hint", update: false);
                droppingAmmoEventArgs.Player.SendRawMsg("scp2686_hint",
                    "这些神奇的子弹只能适用于这把神奇的COM-18!", 3u,
                    ScreenLocation.CenterTop,
                    update: true);
            }

            if (exiledEvent is SearchingPickupEventArgs { IsAllowed: true } searchingPickupEventArgs)
            {
                ItemCategory itemCategory = searchingPickupEventArgs.Pickup.Type.GetCategory();
                if (searchingPickupEventArgs.Player == player && (itemCategory != ItemCategory.Medical &&
                                                                  itemCategory != ItemCategory.Keycard &&
                                                                  searchingPickupEventArgs.Pickup.Type !=
                                                                  ItemType.SCP500 &&
                                                                  searchingPickupEventArgs.Pickup.Serial != serial &&
                                                                  CustomItem.CustomItem.GetItem(searchingPickupEventArgs
                                                                      .Pickup.Serial) is not MiniMicroHID.MiniMicroHID))
                {
                    searchingPickupEventArgs.IsAllowed = false;
                    player.DeleteMsg("scp2686_hint", update: false);
                    player.SendRawMsg("scp2686_hint", "<color=red>你只能拾起 钥匙卡 和 医疗物品!</color>", 3u,
                        ScreenLocation.CenterTop, update: true);
                }
            }

            if (exiledEvent is HurtingEventArgs { IsAllowed: true } ev && ev.DamageHandler.Base is AttackerDamageHandler && ev.Attacker != ev.Player && ev.Attacker != null)
            {
                if (ev.Player == player)
                {
                    var attack_cc = ev.Attacker.GetCharacterInstance();
                    if (attack_cc is Scp2686 or Scp26862)
                    {
                        ev.Amount = 0f;
                        ev.IsAllowed = false;
                        return true;
                    }
                }
                else if (ev.Attacker == player)
                {
                    var cc = ev.Player.GetCharacterInstance();
                    if (cc is Scp2686 or Scp26862)
                    {
                        ev.Amount = 0f;
                        ev.IsAllowed = false;
                        return true;
                    }
                }

                energy = Math.Min(energy + (int)Math.Floor(ev.Amount / 2f), (int)info.Datas["MAX_ENERGY"]);
                info.Datas["energy"] = energy;
                return true;
            }

            if (exiledEvent is HandcuffingEventArgs { IsAllowed: true } handcuffingEventArgs &&
                handcuffingEventArgs.Target == player)
            {
                handcuffingEventArgs.IsAllowed = false;
            }

            if (exiledEvent is ItemRemovedEventArgs itemRemovedEventArgs && itemRemovedEventArgs.Item.Serial == serial)
            {
                itemRemovedEventArgs.Item.Destroy();
                itemRemovedEventArgs.Pickup.Destroy();
            }

            if (exiledEvent is ReloadingWeaponEventArgs { IsAllowed: true } reloadingWeaponEventArgs &&
                reloadingWeaponEventArgs.Firearm.Serial == serial)
            {
                player.SetAmmo(reloadingWeaponEventArgs.Firearm.AmmoType,
                    (ushort)(reloadingWeaponEventArgs.Firearm.MaxAmmo - reloadingWeaponEventArgs.Firearm.Ammo));
            }

            if (exiledEvent is UnloadingWeaponEventArgs { IsAllowed: true } unloadingWeaponEventArgs)
            {
                if (unloadingWeaponEventArgs.Item.Serial == serial)
                {
                    unloadingWeaponEventArgs.IsAllowed = false;
                    unloadingWeaponEventArgs.Player.SendFormattedMsg("item", "<color=#01F1F1>自定义物品</color>",
                        "此武器不能被卸载弹药", 2,
                        MsgType.Failed_Response, ScreenLocation.CenterTop, true);
                }
            }

            if (exiledEvent is UpgradingInventoryItemEventArgs { IsAllowed: true } upgradingInventoryItemEventArgs)
            {
                if (upgradingInventoryItemEventArgs.Item.Serial == serial)
                {
                    upgradingInventoryItemEventArgs.IsAllowed = false;
                }
            }

            info.Datas["energy"] = energy;
            return new AbilityOutput(true);
        }

        public override void Role_Activate()
        {
            base.Role_Activate();
            Player.AddItem(ItemType.KeycardMTFOperative);
            CustomItem.CustomItem.Give(Player, typeof(MiniMicroHID.MiniMicroHID));
            Player.Scale = Vector3.one * 1.1f;
            if (VoiceChatManager.CustomChannels.All(x => x.Id != "Scp2686"))
            {
                VoiceChatManager.VC_CreateChannel(new CustomChannel("Scp2686", "SCP-2686", "#c34616", true));
            }

            Player.VC_AddSender("Scp2686");
            Player.VC_AddListener("Scp2686");
            //todo 删掉
            if (!CommandProcessor.RemoteAdminCommandHandler.TryGetCommand("s26", out _))
            {
                CommandProcessor.RemoteAdminCommandHandler.RegisterCommand(new Scp2686Command());
            }
        }

        public override void Role_Deactive()
        {
            base.Role_Deactive();
            Player.VC_RemoveSender("Scp2686");
            Player.VC_RemoveListener("Scp2686");
            Timing.CallDelayed(0.5f, () =>
            {
                Player.Scale = Vector3.one;
                Player.DeleteMsg("scp2686_hint", update: false);
            });
        }

        private static AbilityInfo GetScp2686Attribute(Player player)
        {
            AbilityInfo ab = player.GetAbility("Scp2686_Attribute_1");
            if (ab.Ability is null)
            {
                ab = player.GetAbility("Scp26862_Attribute_1");
            }

            return ab;
        }

        //todo 这里是测试用 记得删掉这里!!!
        public class Scp2686Command : ICommand
        {
            public bool Execute(ArraySegment<string> arguments, ICommandSender sender, out string response)
            {
                if (arguments.ElementAt(0) == "s")
                {
                    SpawnPlayer<Scp26862>(Player.Get(arguments.ElementAt(1)));
                    response = "已换!";
                    return true;
                }

                AbilityInfo ab = GetScp2686Attribute(Player.Get(sender));
                if (ab.Ability == null)
                {
                    response = "为空!";
                    return false;
                }


                if (int.TryParse(arguments.ElementAt(0), out int en))
                {
                    response = $"成功更改能量为:{en}";
                    ab.Datas["energy"] = en;
                    return true;
                }

                response = "nice";
                return true;
            }

            public string Command => "s26";
            public string[] Aliases => [];
            public string Description => "";
        }
    }
}